#include <iostream>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct symbol;

std::vector<symbol> stree;
int sc=0;

FILE *pFile;
int fc=0;
int flen=0;
std::vector<char> afile;
char *file;
char bchar[] = {' ', '\n', '\r', 9};
char achar[] = {'\"', '\''};
char echar[] = {'\\'};
#define BCHAR_CODES 4
#define ACHAR_CODES 2
#define ECHAR_CODES 1

char wchar[] = {'+', '*', '/', '-', '^', '~', '='};
#define WCHAR_CODES 7

char matchar[] = {'+', '*', '/', '-', '^', '~'};
#define MATCHAR_CODES 6

char asschar[] = {'='};
#define ASSCHAR_CODES 1

char termchar[] = {';'};
#define TERMCHAR_CODES 1

char conchar[] = {','};
#define CONCHAR_CODES 1

char beginchar[] = {'{'};
#define BEGINCHAR_CODES 1

char endchar[] = {'}'};
#define ENDCHAR_CODES 1

char openchar[] = {'('};
#define OPENCHAR_CODES 1

char closechar[] = {')'};
#define CLOSECHAR_CODES 1

const char *funcstr[] = {"func"};
#define FUNCSTR_CODES 1

const char *callstr[] = {"call"};
#define CALLSTR_CODES 1

const char *declstr[] = {"int", "char", "float", "void"};
#define DECLSTR_CODES 3

char pointchar[] = {'*'};
#define POINTCHAR_CODES 1

char logicalchar[] = {'+', '*', '/', '-', '^', '~', '=', ';', ',', '{', '}', '(', ')'};
#define LOGICALCHAR_CODES 13

///defines the logical separators for part 2 of symbolic conversion

char *get_next_word(bool incfl, int &len)
{
    int t=fc;
    int tlen=0;
    bool isb=false;
    bool aset[ACHAR_CODES];
    bool eset=false;
    for(int i=0; i<ACHAR_CODES; i++)
    {
        aset[i]=false;
    }

    while(!isb)
    {
        for(int i=0; i<BCHAR_CODES; i++)
        {
            if(file[t]==bchar[i] || file[t]=='\0')
            {

                isb=true;
                if(file[t]=='\0')
                {
                    len=0;
                    return NULL;
                }
                for(int j=0; j<ACHAR_CODES; j++)
                {
                    if(aset[j])
                    {
                        isb=false;
                        break;
                    }
                }
                break;
            }
        }
        for(int i=0; i<ACHAR_CODES; i++)
        {
            if(file[t]==achar[i] && !eset)
            {
                aset[i]=!aset[i];
            }
        }

        bool prov=false;
        for(int i=0; i<ECHAR_CODES; i++)
        {
            if(file[t]==echar[i] && !eset)
            {
                prov=true;
            }
        }
        eset=prov;

        if(!isb)
        {
            t++;
            tlen++;
        }
    }

    while(isb)
    {
        bool tlc=false;
        for(int i=0; i<BCHAR_CODES; i++)
        {
            if(file[t]==bchar[i])
            {
                tlc=true;
            }
        }
        if(tlc)
        {
            t++;
        }
        else
        {
            break;
        }

    }

    len=tlen;
    char *wstart = &file[fc];
    if(incfl)
    {
        fc=t;
    }
    return wstart;
}

///load_next_symbol


namespace stype
{
    enum s
    {
        start = 's',
        stop = 't',
        mspression = 'e', ///must be broken down further
        func = 'f',
        decl = 'd', ///int etc
        var = 'v', ///name
        mop = 'm', ///mathematical operator, includes = for tree purpose
        point = '*',
        fcall = 'c',
        cont = ',' , ///comma
        term = ';',
        none = '0',
        fargs = 'a'

    };
}

//typedef stype stype;


struct symbol
{
    std::vector<symbol> subsymbols;
    std::vector<int> subpos;
    char *mem;
    int len;
    stype::s type;

    symbol()
    {
        type=stype::none;
    }

};

/*int pointer_peek(bool rem)
{

    char *w; int l=0;
    w = get_next_word(false, l);
    char *endw=w;
    int pcount=0;
    bool pcf=false;
    std::vector<bool> words_consumed;
    while(!pcf)
    {
        bool found=false;
        for(int i=0; i<POINTCHAR_CODES; i++)
        {
            if(w[pcount] == pointchar[i])
            {
                pcount++;
                found=true;
            }
        }
        int sub=0;
        if(pcount >= l)
        {
            endw = get_next_word(true, l); ///consume the full pointer word
            if(words_consumed.size() > 0)
            {
                sub = words_consumed[words_consumed.size()-1];
            }

            words_consumed.push_back(pcount - sub);
            endw = get_next_word(false, l);///dispatch the next word which may contain pointers.
        }
        if(!found)
        {
            pcf=true;
        }
    }
    int subr = 0;
    int offset = 0;
    if(words_consumed.size() > 0)
    {
        subr = words_consumed[words_consumed.size()-1];
    }


}*/

int construct_next_word() ///generates second half of symbol string
{
    symbol cons;
    //stype::s typ;
    int l=0;
    char *w = get_next_word(true, l); ///generates first 'half' of symbol string. Separated words with minimal processing, other than " " non removal. All non essential spaces removed

    std::vector<symbol> symb;

    int li=0;

    if(w==NULL)
    {
        //std::cout << "hi" << std::endl;
        return 1;
    }

    for(int i=0; i<l; i++)
    {
        //printf("%c", w[i]);
        for(int j=0; j<LOGICALCHAR_CODES; j++)
        {

            if(w[i]==logicalchar[j])
            {

                ///we've found a logical split, split!

                symbol one;
                one.len = i - li;
                one.mem = &w[li];

                symbol op;
                op.len = 1;
                op.mem = &w[i];

                if(i-li!=0)
                {
                    stree.push_back(one);
                }

                stree.push_back(op);

                li = i+1;

            }
        }
    }

    symbol last;
    last.len = l - li;
    last.mem = &w[li];

    if(last.len!=0)
        stree.push_back(last);

    return 0;
    //stree.push_back(symb);


}

bool is_operator(char c)
{
    for(int i=0; i<LOGICALCHAR_CODES; i++)
    {
        if(logicalchar[i]==c)
        {
            return true;
        }
    }
    return false;
}

/*symbol root_bracket_symboltree_construct(int lsc, int &processed)
{
    int basec=lsc;
    symbol *T = &stree[lsc];

    printf("hi\n");

    if(T->len!=1)
    {
        std::cout << "something went horribly wrong in root_bracket_symboltree_construct" << std::endl;
        std::cout << T->len << std::endl;
        printf("Symbol: %.*s", T->len, T->mem);
    }
   // printf("Symbol: %.*s", T->len, T->mem);
    int bcount=1;
    lsc++;

    symbol tjoin;
    tjoin.type=stype::mspression;
    bool openf=false;
    while(bcount>0)
    {
        T = &stree[lsc];
        printf("%.*s ", T->len, T->mem);
        openf=false;
        if(T->len==1)
        {
            for(int i=0; i<CLOSECHAR_CODES; i++)
            {
                if(T->mem[0]==closechar[i])
                {
                    printf("I will cut you with a knife\n");
                    //processed=processed-1;
                    bcount--;
                    return tjoin;
                    ///end symbol
                }
            }
            for(int i=0; i<OPENCHAR_CODES; i++)
            {
                if(T->mem[0]==openchar[i])
                {
                    printf("subbracket ");
                    bcount++;
                    int tp=0;
                    symbol sym = root_bracket_symboltree_construct(lsc, tp);
                    processed = processed + tp;
                    lsc+=tp;
                    tjoin.subsymbols.push_back(sym);
                    openf=true;
                    ///begin new symbol
                }
            }
        }



        if(bcount > 0 && !openf)
        {
           // printf("Symbol: %.*s ", stree[lsc].len, stree[lsc].mem);
            tjoin.subsymbols.push_back(stree[lsc]);
            lsc++;
            processed++;
        }

    }



}*/

int distance_to_bracket(int lsc, int &which)
{
    int tdist=0;
    while(tdist + lsc < afile.size())
    {
        symbol *T = &stree[lsc + tdist];
        if(T->len==1)
        {
            for(int i=0; i<CLOSECHAR_CODES; i++)
            {
                if(T->mem[0]==closechar[i])
                {
                    which=0;
                    //dist = tdist;
                    return tdist;
                }
            }

            for(int i=0; i<OPENCHAR_CODES; i++)
            {
                if(T->mem[0]==openchar[i])
                {
                    which=1;
                    //dist = tdist;
                    return tdist;
                }
            }

        }

        tdist++;
    }

}

symbol root_bracket_symboltree_construct(int lsc, int &advance)
{
    ///first symbol is always a bracket
    int bcount=1;
    lsc++;
    int proc=0;
    symbol toret;
    toret.type=stype::mspression;
    toret.len=0;
    int tlc=lsc;
    int dist=0;

    while(bcount!=0)
    {
        symbol *T = &stree[tlc];
        int which;
        int dist = distance_to_bracket(tlc, which);
        for(int i=tlc; i<tlc + dist; i++)
        {
            toret.subsymbols.push_back(stree[i]);
        }
        tlc += dist + 1;
        if(which==0)
        {
            advance+= tlc - lsc -1;
            return toret;
        }
        if(which == 1)
        {
            int len=0;
            symbol symb = root_bracket_symboltree_construct(tlc, len);
            tlc += len;
            advance += len;
            toret.subsymbols.push_back(symb);
        }

        tlc++;
    }

    /*while(bcount!=0)
    {
        symbol *T = &stree[lsc + dist];
        if(T->len==1)
        {
            for(int i=0; i<CLOSECHAR_CODES; i++)
            {
                advance = dist + 1;
                return toret;

            }
            for(int i=0; i<OPENCHAR_CODES; i++)
            {
                int len=0;
                symbol symb = root_bracket_symboltree_construct(lsc + dist, len);
                dist = dist + len;
                advance = advance + len;
                toret.subsymbols.push_back(symb);f

            }
        }
        dist++;
        toret.subsymbols.push_back(*T);
    }*/

    /*while(bcount > 0)
    {
        symbol *T = &stree[lsc];

        if(T->len==1)
        {
            for(int i=0; i<CLOSECHAR_CODES; i++)
            {
                if(T->mem[0]==closechar[i])
                {
                    bcount--;
                    advance = proc + 1;
                    toret.subsymbols.push_back(*T);
                    return toret;

                }
            }
            for(int i=0; i<OPENCHAR_CODES; i++)
            {
                if(T->mem[0]==openchar[i])
                {
                    bcount++;
                    int tad=0;
                    root_bracket_symboltree_construct(lsc, tad);
                    advance += tad;
                    lsc+=tad;
                }
            }

        }
        toret.subsymbols.push_back(*T);
        proc++;
        lsc++;

    }*/







}

void bracket_tree(int lsc)
{
    symbol *T = &stree[lsc];

    std::vector<symbol> mexp;

    if(T->len==1)
    {
        if(is_operator(T->mem[0]))
        {
            char c = T->mem[0];
            for(int i=0; i<OPENCHAR_CODES; i++)
            {

                bool funcdec=false;
                bool funccall=false;

                if(c == openchar[i])
                {
                    if(lsc >= 3 && stree[lsc - 3].type == stype::func)
                    {
                        printf("functiondeclaration");
                        funcdec=true;
                    }
                    else if(lsc >= 2 && stree[lsc - 2].type == stype::fcall)
                    {
                        printf("functioncall");
                        funccall=true;
                    }
                    else ///mexpression. Find closing bracket. If open bracket, pass child to child and point to it, set pos in thing to be whatever
                    {
                        printf("found mspression: %c", T->mem[0]);
                        symbol r_symb;
                        r_symb.type = stype::mspression;
                        int rel=0;
                        r_symb = root_bracket_symboltree_construct(lsc, rel);
                        for(int k=lsc; k<lsc+rel; k++)
                        {
                            stree.erase(stree.begin() + lsc); ///remove k things
                        }
                        stree.insert(stree.begin() + lsc - 1, r_symb);
                        break;
                        //int i=lsc,
                        /*bool bfound=false;
                        int tlsc=lsc;
                        while(!bfound)
                        {
                            char c = stree[tlsc].mem[0];
                            if(stree[tlsc].len!=1)
                            {
                                tlsc++;
                                if(tlsc > stree.size())
                                {
                                    exit(1);
                                    std::cout << "Missing bracket in symbol no: " << lsc << std::endl;
                                }

                                continue;
                            }
                            if(!is_operator(c))
                            {
                                tlsc++;
                                continue;
                            }
                            for(int j=0; j<CLOSECHAR_CODES; j++)
                            {
                                if(closechar[j]==c) ///found closing bracket, put everything between here and there in there. Have to deal with opening brackets first to create
                                                    ///sub things first
                                {

                                }
                            }

                            tlsc++;
                        }*/
                    }
                }

            }
        }
    }


}

void first_pass_symbols()
{
    for(int i=0; i<stree.size(); i++)
    {
        for(int j=0; j<FUNCSTR_CODES; j++)
        {
            int len = strlen(funcstr[j]) > stree[i].len ? strlen(funcstr[j]) : stree[i].len;
            if(strncmp(funcstr[j], stree[i].mem, len)==0)
            {
                stree[i].type = stype::func;
            }
        }
        for(int j=0; j<CALLSTR_CODES; j++)
        {
            int len = strlen(callstr[j]) > stree[i].len ? strlen(callstr[j]) : stree[i].len;
            if(strncmp(callstr[j], stree[i].mem, len)==0)
            {
                stree[i].type = stype::fcall;
            }
        }

        for(int j=0; j<DECLSTR_CODES; j++)
        {
            int len = strlen(declstr[j]) > stree[i].len ? strlen(declstr[j]) : stree[i].len;
            if(strncmp(declstr[j], stree[i].mem, len)==0)
            {
                stree[i].type = stype::decl;
            }

        }


    }

}

void create_symbols()
{
    for(sc=0; sc<stree.size();)
    {
        bracket_tree(sc);
        sc++;
    }
}


void load_file(std::string filename)
{
    FILE *pFile=fopen(filename.c_str(), "r");

    if(pFile==NULL)
    {
        std::cout << "invalid file name in load_file.cpp" << std::endl;
        return;
    }

    while(!feof(pFile))
    {
        char character=fgetc(pFile);
        afile.push_back(character);
    }

    file = afile.data();
    flen = afile.size();

    fclose(pFile);

}


int main()
{
    load_file("ex.txt");

    int len=0;
    char *w;

    while(construct_next_word()!=1)
    {

    }

    first_pass_symbols();

    create_symbols();

    for(int i=0; i<stree.size(); i++)
    {
        printf("%.*s ", stree[i].len, stree[i].mem);
    }

    /*(while((w=get_next_word(true, len))!=NULL)
    {
        //std::cout << w << std::endl;
        printf("%.*s", len, w);
    }*/

    return 0;
}
